home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
TCL1
/
CEDITOR_
/
CEDITORP.C1
< prev
next >
Wrap
Text File
|
1990-06-10
|
10KB
|
340 lines
/******************************************************************************
CEditorPane.c
The EditorPane Class
Subclass of CEditText that implements a full text editor pane with undo
capabilities for the edit menu commands and for typing. This implementation
was inspired by an article in "The Essential Mac Tutor" by Melvyn D. Magree.
Written by Johan A. Goossens
CompuServe: 74010,2576
SUPERCLASS = CEditText.c
******************************************************************************/
#include <CBartender.h>
#include "CEditorPane.h"
extern CBartender *gBartender;
static long cmdSelectAll;
static Boolean first = TRUE;
#define delete 8
#define tab 9
#define retn 13
#define clear 27
#define cursLeft 28
#define cursRight 29
#define cursUp 30
#define cursDown 31
/******************************************************************************
IEditorPanePane
Initialize an EditorPane object.
All parameters are standard, with the exception of firstTaskIndex.
This should give the index into the STR# 130 (STRtaskNames) resource
where the undo strings reside. Strings for cut,copy,paste,clear,type
and delete are required (and in that order). firstTaskIndex gives the
index for cut.
******************************************************************************/
void CEditorPane::IEditorPane(CView *anEnclosure, CBureaucrat *aSupervisor,
int aWidth, int aHeight,
int aHEncl, int aVEncl,
SizingOption aHSizing, SizingOption aVSizing,
int aLineWidth, int theTaskIndex)
{
short itemNo;
CEditText::IEditText(anEnclosure, aSupervisor, aWidth, aHeight, aHEncl,
aVEncl, aHSizing, aVSizing, aLineWidth);
itsCurrentTask = NULL;
itsTaskIndex = theTaskIndex;
typing = 0;
if (first)
{
itemNo = gBartender->FindItemText(MENUedit, (StringPtr) "\pSelect All");
if (itemNo)
cmdSelectAll = gBartender->FindCmdNumber(MENUedit, itemNo);
first = FALSE;
}
}
/******************************************************************************
UpdateMenus {OVERRIDE}
Perform menu management tasks.
Enable the "Select All" menu if one exists.
******************************************************************************/
void CEditorPane::UpdateMenus()
{
inherited::UpdateMenus();
if (cmdSelectAll)
gBartender->EnableCmd(cmdSelectAll);
}
/******************************************************************************
DoCommand {OVERRIDE}
Perform the required commands. This method is a bit tricky. It is
called by the TCL. In this case a new task must be created to support
the undo capabilities. It is also called by the tasks to perform
all actions required for do, undo and redo. In this case no new task
should be created to avoid a perfect endless loop.
To support this logic, new command values are used for the various
edit commands. These new values are only used by the task manager,
so it becomes easy to determine whether the TCL called us or the
task called us.
******************************************************************************/
void CEditorPane::DoCommand(long theCommand)
{
typing = 0;
if ((theCommand >= cmdCut) && (theCommand <= cmdClear))
{
itsCurrentTask = new(CEditorTask);
itsCurrentTask->IEditorTask(this, itsTaskIndex, cmdOffset + theCommand);
itsCurrentTask->Do();
itsSupervisor->Notify(itsCurrentTask);
}
else
if (theCommand == cmdSelectAll)
SelectAll();
else
if ((theCommand >= cmdMyCut) && (theCommand <= cmdMyClear))
inherited::DoCommand(theCommand - cmdOffset);
else
inherited::DoCommand(theCommand);
}
/******************************************************************************
DoClick {OVERRIDE}
Reset the typing indicator to make sure that a new task will be
created on the next keystroke.
******************************************************************************/
void CEditorPane::DoClick(Point hitPt, short modifierKeys, long when)
{
typing = 0;
inherited::DoClick(hitPt, modifierKeys, when);
}
/******************************************************************************
DoKeyDown {OVERRIDE}
Handle keystrokes. A typing indicator is used to determine whether a
new typing task must be created. A sequence of keystrokes are collected
into one task. This indicator is reset by other commands and by the
undo mechanism. The value of the indicator specifies the number of
keystrokes in the current typing task.
The delete key is special. If this key is pressed when the typing
indicator is greater then zero, it is treated as part of the typing
task and all indicators and counters are adjusted. If the key is
pressed when the typing indicator is zero, it is treated as a seperate
command and a new task is created. If the delete key if pressed if the
current caret location is zero, we "beep" and ignore the command.
The following keystrokes are supported at the moment:
Cursor: left, right, up and down.
These key are not translated into tasks since they don't change
the text and and can't be undone.
Clear:
This key is translated into the menu command "cmdClear".
Delete:
See above.
All ASCII values between 32 (space) and 127 (~):
These values are translated into a typing task. See discussion
above.
All other values:
In all other cases, we just "beep" and ignore the keystroke.
******************************************************************************/
void CEditorPane::DoKeyDown(char theChar, Byte keyCode, EventRecord *macEvent)
{
switch (theChar)
{
case cursLeft:
case cursRight:
case cursUp:
case cursDown:
inherited::DoKeyDown( theChar, keyCode, macEvent);
break;
case clear:
DoCommand(cmdClear);
break;
case delete:
if ((**macTE).selEnd == 0)
{
SysBeep(1);
return;
}
if (typing)
{
itsCurrentTask->Typing(-1);
typing--;
}
else
{
itsCurrentTask = new(CEditorTask);
itsCurrentTask->IEditorTask(this, itsTaskIndex, cmdMyDelete);
itsCurrentTask->Do();
itsSupervisor->Notify(itsCurrentTask);
}
inherited::DoKeyDown(theChar, keyCode, macEvent);
break;
default:
if ((theChar < 32 || theChar > 127)
&& theChar != tab && theChar != retn)
{
SysBeep(1);
return;
}
if (typing)
{
itsCurrentTask->Typing(+1);
typing++;
}
else
{
itsCurrentTask = new(CEditorTask);
itsCurrentTask->IEditorTask(this, itsTaskIndex, cmdMyTyping);
itsCurrentTask->Do();
itsSupervisor->Notify(itsCurrentTask);
typing = 1;
}
inherited::DoKeyDown(theChar, keyCode, macEvent);
break;
}
}
/******************************************************************************
GetSize
Get the size of the TextEdit buffer.
******************************************************************************/
void CEditorPane::GetSize(long *length, long *lines)
{
*length = (**macTE).teLength;
*lines = (**macTE).nLines;
}
/******************************************************************************
GetSelection
Get the current selection parameters.
******************************************************************************/
void CEditorPane::GetSelection(long *startSel, long *endSel)
{
*startSel = (**macTE).selStart;
*endSel = (**macTE).selEnd;
}
/******************************************************************************
SetSelection
Set the current selection parameters.
******************************************************************************/
void CEditorPane::SetSelection(long startSel, long endSel)
{
Prepare();
TESetSelect(startSel, endSel, macTE);
}
/******************************************************************************
SelectAll
Set the current selection to the whole text.
******************************************************************************/
void CEditorPane::SelectAll( void)
{
SetSelection( 0, MAXINT);
}
/******************************************************************************
GetCharacter
Get the character at a certain position.
******************************************************************************/
char CEditorPane::GetCharacter(long position)
{
return *(*((**macTE).hText) + position);
}
/******************************************************************************
GetSelectionHandle
Copy the current selection into a handle. If no selection exists
the handle pointer is set to NULL and FALSE is returned to the caller.
Otherwise TRUE will be returned.
******************************************************************************/
Boolean CEditorPane::GetSelectionHandle(Handle *data)
{
long startSel, endSel;
GetSelection(&startSel, &endSel);
if (startSel == endSel)
{
data = NULL;
return(FALSE);
}
else
{
*data = NewHandle(endSel - startSel);
BlockMove(*((**macTE).hText) + startSel, **data, endSel - startSel);
return(TRUE);
}
}
/******************************************************************************
SetSelectionHandle
Replace the current selection with the data in a handle.
******************************************************************************/
void CEditorPane::SetSelectionHandle(Handle data)
{
long startSel, endSel;
long size;
Prepare();
GetSelection(&startSel, &endSel);
TEDelete(macTE);
size = GetHandleSize(data);
HLock(data);
TEInsert(*data, size, macTE);
HUnlock(data);
SetSelection(startSel, startSel + size);
}
/******************************************************************************
ResetTyping
Reset the typing indicator.
******************************************************************************/
void CEditorPane::ResetTyping(void)
{
typing = 0;
}